iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 9
1
自我挑戰組

Hey! UIKit, 做個朋友吧~系列 第 9

Day 09: 我94要分段控制!哈囉控制狂UISegmentedControl

  • 分享至 

  • xImage
  •  

UISegmentedControl: 可以不要污名化我嗎+_+?
邊緣人:怕豹.jpg


segmented control(分段控制器),可以使title或image甚至是其他view在不同的分段中有不同的顯示。對應的UIEvent為valueChange。
早期如果segmented只有2個的話會變得跟switch一樣,只要輕觸被選取的segmented就會切換到另一segmented,而這在iOS 3.0之後被改掉了。

建立segmentedControl

首先先初始化一個UISegmentedControl實體...都講幾百次了啊~
不過比較特別的是UISegmentedControl是可以客製化的,可以在初始化時指定一個[Any]作為Segmented的內容,例如我們先建立一個UIImage的陣列

let segmentedContent = [UIImage(named: "finn"), UIImage(named: "jack"), UIImage(named: "beemo"), UIImage(named: "princessBubblegum"), UIImage(named: "marceline"), UIImage(named: "iceKing")]

再把這個陣列於初始化時指定給segmentedControl:

let newSegmentedControl = UISegmentedControl(items: segmentedContent as [Any])

我的segmentedControl就會變成...

啊咧@__@我的活寶照片怎麼變成剪影了
點擊的時候還會反白耶哈哈哈

content

segmented的內容可以是字串也可以是圖片,除了剛剛用陣列的方式指定以外,也可以利用以下方法設定:

newSegmentedControl.setTitle("A", forSegmentAt: 0)
newSegmentedControl.setImage(UIImage(named: "finn"), forSegmentAt: 1)
newSegmentedControl.setTitle("B", forSegmentAt: 2)
newSegmentedControl.setImage(UIImage(named: "jack"), forSegmentAt: 3)
newSegmentedControl.setTitle("C", forSegmentAt: 4)
newSegmentedControl.setImage(UIImage(named: "princessBubblegum"), forSegmentAt: 5)


順帶一提,segmented的index是zero base。

segment可以設定文字跟圖片,也可以把他們叫出來:

segmentedImageView.image = newSegmentedControl.imageForSegment(at: 1)
segmentedTitle.text = newSegmentedControl.titleForSegment(at: 4)


原來第2張圖片是阿寶啊~
另外也可以使用numberOfSegments回傳segment的個數。

綜合以上所學,我們就可以寫個簡單的action,在不同的segment下指定相對應的圖片,印出最一開始初始化的segmentedControl的圖案。

@objc func segmentChange(_ sender: UISegmentedControl) {
    switch newSegmentedControl.selectedSegmentIndex {
    case 0...newSegmentedControl.numberOfSegments-1:
        segmentedImageView.image = newSegmentedControl.imageForSegment(at: newSegmentedControl.selectedSegmentIndex)
    default:
        break
    }
}

插入segment

segment可以在指定的索引位置裡增加分段:

newSegmentedControl.insertSegment(with: UIImage(named: "marceline"), at: 0, animated: true)


如圖所示,我們在索引位置0的部分加入了艾薇兒的圖片。
而imageView跟label是在插入前指定的,所以還是顯示C跟阿寶的圖片,並沒有被插入segment的動作所影響。
順帶一提,如果要插入文字的話,要用insertSegment(withTitle: at: animated:)這個function。

移除segment

也可以移除指定索引值的segment:

newSegmentedControl.removeSegment(at: 3, animated: true)


或是用removeAllSegments()移除整個segmentedControl

Behavior of Segment

Momentary

如果segmentedControl的isMomentary為true的話,被選取的segmented就不會一直反白,而只在被選取的當下閃一下:

如果不清楚當前選取的segment為哪一個的話,可以使用selectSegmentIndex回傳當前的索引值(剛剛為了範例好像已經不小心劇透了)。

Enable

segmentedControl還可以讓某個segment失效,方法如下:

newSegmentedControl.setEnabled(false, forSegmentAt: 3)


如圖所示,索引值為3的segment變成灰色且無法被選取。
同樣的也可以用isEnabledForSegment(at:)回傳指定索引segment的布林值。

Offset

為什麼要對segment的content做offset?我真的快笑死
阿寶回來啊~~~~

實作的程式碼如下:

newSegmentedControl.setContentOffset(CGSize(width: 10, height: 10), forSegmentAt: 1)

同樣可以用contentOffsetForSegment(at:)回傳當前索引值offset的CGSize。

width

一般segment的寬度都是由segment均分segmentedControl的總寬,如果要對其中一個segment做調整的話做法如下:

newSegmentedControl.setWidth(30, forSegmentAt: 3)


如此一來只有被指定的segment寬度不一樣,其他segment均分剩下的寬度。同樣可以用widthForSegment(at:)來回傳指定索引segment的寬度。
而如果apportionsSegmentWidthsByContent是true的話,segment的寬度就會依內容調整。
如下圖字串的寬度依內容調整,剩下的寬度被圖片segment均分之後再拉長圖片就成了這副鬼樣子,實在是太好笑了XD

Customize

customize裡有4組function,跟之前一樣有分set跟get。

Background Image

可以設定整條segmentedControl的背景圖片。
要注意的是如果設定了selected的的背景圖片,一定要同時設定normal狀態下的,不然他如果沒有圖片可以切換的話就會無法顯示。

newSegmentedControl.setBackgroundImage(UIImage(named: "finn"), for: .normal, barMetrics: .default)
newSegmentedControl.setBackgroundImage(UIImage(named: "jack"), for: .selected, barMetrics: .default)


如圖我設定整段segmentedControl的背景圖片為阿寶,但被我點選的segment會切換成selected state,就會顯示老皮的圖片。
一樣可以使用backgroundImage(for:barMetrics:)取出不同state的背景圖片。

Content Position Adjustment

這個function顧名思義就是調整segment內容的位置,一樣可以用contentPositionAdjustment(forSegmentType:barMetrics:)回傳一個UIOffset

newSegmentedControl.setContentPositionAdjustment(UIOffset(horizontal: 10, vertical: 10), forSegmentType: UISegmentedControl.Segment(rawValue: 0)!, barMetrics: .default)


有個搞不太清楚的新發現是:rawValue決定了offset的segment,但不知道為何這樣定義。
0:全部segment內容offset
1:只有第一個會offset
2:除第一個和最後一個之外,其他offset
3:只有最後一個offset
4之後這個function對segment都沒有影響,沒有segment會offset。

Divider Image

divider設定了一個image來取代分隔線,用dividerImage(forLeftSegmentState:rightSegmentState:barMetrics:)取出image。

newSegmentedControl.setDividerImage(UIImage(named: "dot"), forLeftSegmentState: .selected, rightSegmentState: .selected, barMetrics: .default)


不過神奇的是,我state不管怎麼改,segment怎麼選都不會有變化QQstate到底是幹嘛用的啊

Title Text Attributes

text attributes客製化了在特定狀態下的title text,
範例設定了在selected的狀態下,title text會變成italic字體並且大小變成50。

newSegmentedControl.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 50)], for: .selected)


NSAttributedString.Key裡還有非常多的屬性可以設定,超好玩的!鼓勵大家可以自己試試看。

那UISegmentedControl就到此告一段落了~
下一回即將進入重頭戲UITextField。
看著他洋溢幸福的暖暖文字們,不知道我撐不撐得住啊...


上一篇
Day 08: 蛤?你說你在哪?我沒看到你啊UIPageControl
下一篇
Day 10: UITextField三部曲-龍紋身的UITextField
系列文
Hey! UIKit, 做個朋友吧~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言